// 等待执行 多次触发 每次执行都会delay秒后 限制调用频率
export const wait = (fn, delay) => {
  let pendingPromise = Promise.resolve()
  let currentToken = { canceled: false } // 当前任务的取消令牌

  const wrappedFn = (...args) => {
    const token = currentToken // 捕获当前令牌
    const resultPromise = pendingPromise.then(() => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (token.canceled) {
            reject(new Error('Task canceled'))
          } else {
            resolve(fn(...args))
          }
        }, delay)
      })
    })

    // 更新待处理链，忽略错误（确保后续任务继续）
    pendingPromise = resultPromise.catch(() => {})
    return resultPromise
  }

  // 添加 cancel 方法
  wrappedFn.cancel = () => {
    // 1. 标记当前令牌为已取消
    currentToken.canceled = true
    // 2. 创建新令牌（后续任务不受影响）
    currentToken = { canceled: false }
    // 3. 重置任务链（后续任务不等待被取消的任务）
    pendingPromise = Promise.resolve()
  }

  return wrappedFn
}

// 分组执行 用于限制qps并发数
export const group = (fn, qps = 3, delay = 1000) => {
  const queue = []
  let isRunning = false
  let lastRunTime = 0

  // 处理队列中的任务
  const processQueue = async () => {
    if (isRunning || queue.length === 0) return

    isRunning = true

    // 计算需要等待的时间
    const now = Date.now()
    const timeSinceLastRun = now - lastRunTime
    const waitTime = Math.max(0, delay - timeSinceLastRun)

    await new Promise((resolve) => setTimeout(resolve, waitTime))

    // 取出最多 qps 个任务执行
    const tasksToRun = queue.splice(0, qps)
    lastRunTime = Date.now()

    // 并行执行任务
    await Promise.all(
      tasksToRun.map((task) => {
        return new Promise((resolve) => {
          try {
            const result = fn(...task.args)
            task.resolve(result)
            resolve()
          } catch (error) {
            task.reject(error)
            resolve()
          }
        })
      }),
    )

    isRunning = false

    // 继续处理剩余任务
    if (queue.length > 0) {
      processQueue()
    }
  }

  return (...args) => {
    return new Promise((resolve, reject) => {
      // 将任务添加到队列
      queue.push({ args, resolve, reject })

      // 如果没有在处理，则启动处理流程
      if (!isRunning) {
        processQueue()
      }
    })
  }
}
